#include <assert.h>
#include <stdio.h>

#include "../src/estep.c"

typedef struct _EstepTestDatum EstepTestDatum ;
struct _EstepTestDatum 
{ 
  struct
    {
      double    priorz[5];
      Rating    ratings[8];
      double    alpha[4 * 5 * 5];
      double    logbeta[3];
    }                   inputs;

  double pz[3*5];
};

static void
test_estep (void)
{
  EstepTestDatum data[] = 
    {{{{0.788009, 0.996442, 0.82066, 0.00248895,  0.906416}, {{0, 0, 0}, {3, 1, 4}, {1, 2, 0}, {2, 2, 0}, {0, 1,  2}, {3, 0, 2}, {2, 1, 0}, {0, 0, 4}}, {0, 0.613471, 0.749282,  0.654335, 0.529157, 0.212059, 0, 0.351128, 0.826862, 0.432094,  0.245815, 0.460571, 0, 0.709696, 0.664574, 0.885258, 0.550973,  0.349347, 0, 0.863038, 0.857708, 0.567922, 0.237935, 0.0750297, 0,  0, 0.861266, 0.747262, 0.235446, 0.168613, 0.247795, 0, 0.99798,  0.581111, 0.639457, 0.0357365, 0.646851, 0, 0.754248, 0.207363,  0.789921, 0.18628, 0.0445519, 0, 0.542788, 0.904663, 0.635307,  0.695205, 0.67975, 0, 0, 0.0469554, 0.0673858, 0.45727, 0.60472,  0.185689, 0, 0.320124, 0.221824, 0.436107, 0.937894, 0.322144, 0,  0.640713, 0.79665, 0.902157, 0.675292, 0.886465, 0, 0.589288,  0.112236, 0.489012, 0.841913, 0.0464992, 0, 0, 0.207573, 0.853705,  0.146709, 0.366749, 0.160617, 0, 0.786319, 0.689439, 0.762029,  0.974928, 0.466195, 0, 0.467615, 0.325922, 0.0370341, 0.144051,  0.826901, 0, 0.529272, 0.134877, 0.468759, 0.940436, 0.939984,  0}, {0.0226406, 0.979747, 0.0985229}}, {0.235047, 0.246098,  0.374269, 0.000216508, 0.144369, 0.0903313, 0.0753046, 0.12205,  0.0000894175, 0.712225, 0.356363, 0.313366, 0.158949, 0.000232553,  0.17109}}, {{{0.893485, 0.815068, 0.126042, 0.951814,  0.526736}, {{1, 1, 3}, {0, 1, 4}, {0, 0, 1}, {2, 1, 4}, {3, 2,  3}, {3, 1, 1}, {1, 1, 2}, {1, 2, 1}}, {0, 0.65445, 0.339723,  0.262375, 0.764707, 0.679522, 0, 0.873528, 0.79476, 0.438785,  0.642488, 0.729476, 0, 0.967859, 0.909513, 0.507612, 0.260717,  0.0274229, 0, 0.969528, 0.484971, 0.28097, 0.9289, 0.0760433, 0,  0, 0.669903, 0.154928, 0.977086, 0.549307, 0.0154528, 0, 0.815205,  0.71471, 0.784601, 0.33593, 0.941678, 0, 0.91995, 0.345816,  0.693442, 0.212201, 0.952091, 0, 0.436303, 0.185831, 0.951484,  0.924668, 0.466775, 0, 0, 0.70086, 0.670514, 0.995768, 0.390732,  0.0309563, 0, 0.515586, 0.0186823, 0.841424, 0.0155035, 0.70038,  0, 0.303972, 0.0568236, 0.679573, 0.758703, 0.384022, 0, 0.711007,  0.986131, 0.546502, 0.431931, 0.274704, 0, 0, 0.8003, 0.595017,  0.507263, 0.807929, 0.0994407, 0, 0.924503, 0.511495, 0.417197,  0.0684844, 0.408918, 0, 0.492813, 0.575773, 0.052981, 0.708537,  0.188841, 0, 0.518949, 0.373408, 0.949834, 0.804819, 0.807942,  0}, {0.387277, 0.403333, 0.372888}}, {0.149702, 0.432286,  0.0253424, 0.253961, 0.138709, 0.239434, 0.203314, 0.0781861,  0.1057, 0.373366, 0.158782, 0.295884, 0.0120604, 0.490681,  0.0425928}}, {{{0.533238, 0.586977, 0.808316, 0.865625,  0.725309}, {{1, 1, 3}, {1, 0, 4}, {2, 1, 0}, {3, 0, 4}, {1, 0,  4}, {2, 1, 1}, {3, 0, 2}, {1, 1, 4}}, {0, 0.487536, 0.883812,  0.35413, 0.308112, 0.419052, 0, 0.474894, 0.861317, 0.732339,  0.366071, 0.766357, 0, 0.672476, 0.213389, 0.992663, 0.816523,  0.867658, 0, 0.405447, 0.605386, 0.41319, 0.49477, 0.872209, 0, 0,  0.0184088, 0.604874, 0.629145, 0.1469, 0.530873, 0, 0.721062,  0.275015, 0.838789, 0.111821, 0.246168, 0, 0.413698, 0.10645,  0.745751, 0.479811, 0.741221, 0, 0.893061, 0.753088, 0.663288,  0.873564, 0.487613, 0, 0, 0.147702, 0.250098, 0.378794, 0.615404,  0.129293, 0, 0.645224, 0.749649, 0.468504, 0.598421, 0.924162, 0,  0.474634, 0.629715, 0.486599, 0.677994, 0.0609363, 0, 0.523265,  0.740849, 0.198183, 0.319715, 0.630204, 0, 0, 0.987761, 0.534895,  0.446151, 0.142591, 0.840059, 0, 0.284797, 0.0673567, 0.527186,  0.710765, 0.639573, 0, 0.317707, 0.0586829, 0.112345, 0.715411,  0.843073, 0, 0.428968, 0.625745, 0.0374166, 0.782137, 0.905703,  0}, {0.884896, 0.839233, 0.462422}}, {0.0775089, 0.003616,  0.406673, 0.00248252, 0.509719, 0.205734, 0.322238, 0.0433373,  0.0859086, 0.342782, 0.151511, 0.16678, 0.22967, 0.245954,  0.206085}}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      double pz[3*5];
      int clamp[3] = { -1, -1, -1 };

      for (unsigned int j = 0; j < 3*5; ++j) { pz[j] = drand48 (); }

      estep (data[i].inputs.alpha,
             5,
             data[i].inputs.logbeta,
             3,
             pz,
             data[i].inputs.priorz,
             clamp,
             data[i].inputs.ratings,
             8,
             0);

      for (unsigned int j = 0; j < 3*5; ++j)
        {
          assert (fabs (pz[j] - data[i].pz[j]) <=
                  1e-4 * (1 + fabs (pz[j]) + fabs (data[i].pz[j])) ||
                  (fprintf (stderr, "%u: %g ?= %g\n", j, pz[j], data[i].pz[j]), 0));
        }
    }
}

typedef struct _EstepClampTestDatum EstepClampTestDatum ;
struct _EstepClampTestDatum 
{ 
  struct
    {
      double    priorz[5];
      Rating    ratings[8];
      double    alpha[4 * 5 * 5];
      double    logbeta[3];
      int       clamp[3];
    }                   inputs;

  double pz[3*5];
};

static void
test_estep_clamp (void)
{
  EstepClampTestDatum data[] = 
    {{{{0.107474, 0.190895, 0.186023, 0.388567,  0.290513}, {{0, 2, 1}, {1, 0, 0}, {2, 1, 4}, {1, 2, 2}, {0, 1,  2}, {1, 2, 1}, {3, 1, 0}, {0, 0, 2}}, {0, 0.929811, 0.609693,  0.24296, 0.92997, 0.779737, 0, 0.643311, 0.928098, 0.0418802,  0.688804, 0.526119, 0, 0.518693, 0.440049, 0.334978, 0.452695,  0.76039, 0, 0.498534, 0.707982, 0.998292, 0.584045, 0.39106, 0, 0,  0.517087, 0.812269, 0.195478, 0.100547, 0.587276, 0, 0.202576,  0.952519, 0.170577, 0.807539, 0.559265, 0, 0.0244207, 0.128697,  0.118735, 0.033146, 0.505728, 0, 0.688648, 0.783756, 0.580451,  0.745338, 0.190113, 0, 0, 0.0757742, 0.582159, 0.161293, 0.799053,  0.558687, 0, 0.76989, 0.965814, 0.698506, 0.971411, 0.567314, 0,  0.0132959, 0.527929, 0.163872, 0.00804874, 0.988875, 0, 0.399233,  0.0451375, 0.974903, 0.483147, 0.710585, 0, 0, 0.261381, 0.394452,  0.737809, 0.520472, 0.185607, 0, 0.812293, 0.576517, 0.721419,  0.62692, 0.0424034, 0, 0.610702, 0.0229127, 0.655508, 0.47509,  0.597406, 0, 0.494983, 0.491636, 0.467041, 0.608531, 0.0957502,  0}, {0.446498, 0.492138, 0.125383}, {-1, -1, -1}}, {0.174,  0.111576, 0.19604, 0.341338, 0.177045, 0.0830981, 0.174296,  0.179191, 0.144971, 0.418443, 0.0243708, 0.454633, 0.139509,  0.299364,  0.0821233}}, {{{0.387574, 0.864693, 0.99951, 0.285393,  0.811057}, {{3, 1, 0}, {3, 0, 0}, {1, 0, 1}, {1, 0, 0}, {3, 1,  4}, {3, 2, 1}, {3, 0, 0}, {0, 1, 1}}, {0, 0.143274, 0.372591,  0.242989, 0.200355, 0.120361, 0, 0.717082, 0.7679, 0.602949,  0.625378, 0.225447, 0, 0.300859, 0.994418, 0.529628, 0.778948,  0.808721, 0, 0.869035, 0.144463, 0.593831, 0.711035, 0.481461, 0,  0, 0.27977, 0.594321, 0.425642, 0.670404, 0.136496, 0, 0.22173,  0.182652, 0.470048, 0.0161347, 0.504647, 0, 0.414753, 0.867099,  0.390757, 0.279201, 0.113894, 0, 0.872681, 0.861129, 0.500253,  0.305173, 0.00364565, 0, 0, 0.716666, 0.906422, 0.594139,  0.522185, 0.436896, 0, 0.312101, 0.168497, 0.851781, 0.3004,  0.0903713, 0, 0.985845, 0.381733, 0.284265, 0.585724, 0.571092, 0,  0.514634, 0.893509, 0.306523, 0.457198, 0.641954, 0, 0,  0.0323798, 0.80627, 0.152025, 0.638308, 0.315714, 0, 0.899849,  0.557887, 0.116123, 0.878818, 0.587747, 0, 0.38939, 0.264342,  0.578418, 0.497376, 0.403545, 0, 0.882609, 0.294153, 0.911652,  0.832453, 0.367975, 0}, {0.400644, 0.605129, 0.375254}, {0, -1,  0}}, {0.999998, 8.73371e-7, 1.45373e-7, 3.15778e-7,  2.4578e-7, 0.0728017, 0.516053, 0.1273, 0.0116409, 0.272204,  0.999993, 2.8422e-6, 1.30594e-6, 1.59956e-6,  8.59117e-7}}, {{{0.223229, 0.0877131, 0.0525503, 0.89901,  0.665343}, {{0, 0, 1}, {2, 1, 0}, {3, 0, 1}, {1, 2, 4}, {1, 1,  3}, {2, 1, 0}, {3, 2, 0}, {3, 1, 2}}, {0, 0.97159, 0.173733,  0.311263, 0.275953, 0.707248, 0, 0.595315, 0.813887, 0.872408,  0.824639, 0.301162, 0, 0.902234, 0.039955, 0.456664, 0.900518,  0.297105, 0, 0.664701, 0.730643, 0.532254, 0.498246, 0.441471, 0,  0, 0.64293, 0.479704, 0.599236, 0.776129, 0.67134, 0, 0.305971,  0.287973, 0.500176, 0.964092, 0.710657, 0, 0.474086, 0.627768,  0.139454, 0.409494, 0.571852, 0, 0.587813, 0.68279, 0.508976,  0.274747, 0.923112, 0, 0, 0.952147, 0.976722, 0.776501, 0.481641,  0.309217, 0, 0.497018, 0.177265, 0.705512, 0.637877, 0.191047, 0,  0.889292, 0.205336, 0.673785, 0.48039, 0.415206, 0, 0.577568,  0.534331, 0.0708956, 0.843354, 0.989755, 0, 0, 0.851541, 0.561919,  0.568608, 0.0666431, 0.899395, 0, 0.585197, 0.792107, 0.585002,  0.590177, 0.0881793, 0, 0.614842, 0.87949, 0.9523, 0.897133,  0.72555, 0, 0.674153, 0.278516, 0.416743, 0.310344, 0.096585,  0}, {0.744185, 0.345847, 0.46699}, {-1, 1, 0}}, {0.0137708,  0.541141, 0.0718341, 0.111155, 0.262098, 7.43669e-6, 0.999988,  1.88508e-6, 1.51157e-6, 7.54996e-7, 0.999993,  9.78068e-7, 1.34035e-6, 8.32617e-7, 4.26296e-6}}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      double pz[3*5];

      for (unsigned int j = 0; j < 3*5; ++j) { pz[j] = drand48 (); }

      estep (data[i].inputs.alpha,
             5,
             data[i].inputs.logbeta,
             3,
             pz,
             data[i].inputs.priorz,
             data[i].inputs.clamp,
             data[i].inputs.ratings,
             8,
             0);

      for (unsigned int j = 0; j < 3*5; ++j)
        {
          assert (fabs (pz[j] - data[i].pz[j]) <=
                  1e-4 * (1 + fabs (pz[j]) + fabs (data[i].pz[j])) ||
                  (fprintf (stderr, "%u: %g ?= %g\n", j, pz[j], data[i].pz[j]), 0));
        }
    }
}

static void
test_estep_symmetric (void)
{
  EstepTestDatum data[] = 
    {{{{0.510627, 0.0281321, 0.94178, 0.563479,  0.981261}, {{1, 0, 0}, {0, 0, 4}, {2, 0, 4}, {0, 2, 4}, {1, 2,  2}, {0, 1, 2}, {2, 2, 1}, {0, 0, 2}}, {0, 0.162404, 0.00241516,  0.214978, 0.724963, 0.549392, 0, 0.103638, 0.637123, 0.653976,  0.0922644, 0.268683, 0, 0.948562, 0.984851, 0.368684, 0.827192,  0.927177, 0, 0.183744, 0.692775, 0.979462, 0.605781, 0.673117, 0,  0, 0.664643, 0.0376818, 0.042302, 0.691856, 0.502239, 0,  0.0352666, 0.827324, 0.966893, 0.952847, 0.931629, 0, 0.190201,  0.312917, 0.860582, 0.662946, 0.241639, 0, 0.328066, 0.491898,  0.835754, 0.314462, 0.144322, 0, 0, 0.799123, 0.856292, 0.70868,  0.471205, 0.13448, 0, 0.818611, 0.666378, 0.779349, 0.632241,  0.783344, 0, 0.839054, 0.812457, 0.679395, 0.851715, 0.648854, 0,  0.49954, 0.818812, 0.188769, 0.407215, 0.171474, 0, 0, 0.326914,  0.353014, 0.0927531, 0.0271521, 0.527791, 0, 0.496722, 0.384073,  0.555947, 0.393311, 0.678111, 0, 0.717694, 0.776597, 0.761069,  0.894767, 0.87864, 0, 0.964141, 0.0816747, 0.0430521, 0.229786,  0.464601, 0}, {0.262862, 0.854284, 0.822571}}, {0.193824,  0.0047156, 0.196377, 0.164992, 0.440091, 0.27233, 0.0140954,  0.586008, 0.0435947, 0.0839724, 0.0512538, 0.0357267, 0.0596055,  0.246749,  0.606665}}, {{{0.293126, 0.935948, 0.501269, 0.729818,  0.265974}, {{1, 0, 3}, {1, 0, 4}, {1, 0, 2}, {1, 1, 3}, {2, 0,  4}, {2, 2, 4}, {3, 1, 1}, {3, 0, 1}}, {0, 0.408157, 0.0045476,  0.345745, 0.710027, 0.0148469, 0, 0.326437, 0.628051, 0.93343,  0.253778, 0.431669, 0, 0.749411, 0.969289, 0.172103, 0.388617,  0.519625, 0, 0.504689, 0.909241, 0.534334, 0.697054, 0.211563, 0,  0, 0.973292, 0.0330644, 0.967236, 0.945588, 0.565135, 0,  0.0285168, 0.621491, 0.235561, 0.550288, 0.70208, 0, 0.99344,  0.302131, 0.29651, 0.270411, 0.244029, 0, 0.332842, 0.124407,  0.881793, 0.724403, 0.828153, 0, 0, 0.215166, 0.34746, 0.0273489,  0.61659, 0.241874, 0, 0.314395, 0.0601125, 0.671002, 0.67674,  0.285879, 0, 0.438621, 0.435441, 0.126452, 0.583798, 0.445181, 0,  0.13331, 0.829942, 0.313387, 0.201152, 0.800468, 0, 0, 0.705535,  0.431594, 0.476749, 0.972316, 0.490368, 0, 0.0841342, 0.4494,  0.355726, 0.248494, 0.769739, 0, 0.389288, 0.684724, 0.571754,  0.48386, 0.950666, 0, 0.249283, 0.445303, 0.900062, 0.505485,  0.115973, 0}, {0.615361, 0.586675, 0.304333}}, {0.00962582,  0.27809, 0.0651666, 0.275532, 0.371585, 0.0252244, 0.319233,  0.0643486, 0.49165, 0.0995433, 0.0762703, 0.228889, 0.18572,  0.322562,  0.186559}}, {{{0.315505, 0.909826, 0.155081, 0.827584,  0.343189}, {{1, 2, 4}, {0, 2, 2}, {3, 2, 0}, {1, 2, 2}, {3, 1,  3}, {0, 1, 2}, {1, 2, 0}, {3, 0, 0}}, {0, 0.419457, 0.0709465,  0.378184, 0.987463, 0.170963, 0, 0.301208, 0.988896, 0.302739,  0.599209, 0.817347, 0, 0.0382301, 0.0534564, 0.153906, 0.917285,  0.532745, 0, 0.937483, 0.538546, 0.33061, 0.228412, 0.621979, 0,  0, 0.62872, 0.17553, 0.400828, 0.27879, 0.209263, 0, 0.104583,  0.0226439, 0.291327, 0.0382995, 0.803376, 0, 0.0337475, 0.988588,  0.439091, 0.986029, 0.995517, 0, 0.935131, 0.285185, 0.0687435,  0.462773, 0.997648, 0, 0, 0.746639, 0.738133, 0.234361, 0.375669,  0.117919, 0, 0.562603, 0.833533, 0.0968788, 0.908656, 0.45802, 0,  0.810889, 0.805552, 0.870357, 0.654644, 0.777141, 0, 0.816964,  0.431266, 0.668616, 0.781624, 0.881833, 0, 0, 0.146082, 0.599872,  0.318851, 0.884185, 0.399443, 0, 0.861739, 0.0844906, 0.508517,  0.281524, 0.299136, 0, 0.250958, 0.411638, 0.372867, 0.841116,  0.440069, 0, 0.606086, 0.502511, 0.186472, 0.662928, 0.789122,  0}, {0.0712445, 0.517856, 0.881304}}, {0.175954, 0.402828,  0.0474467, 0.291518, 0.0822535, 0.10526, 0.293381, 0.0500868,  0.460025, 0.0912479, 0.783607, 0.114356, 0.00725769, 0.0561511,  0.0386282}}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      double pz[3*5];
      int clamp[3] = { -1, -1, -1 };

      for (unsigned int j = 0; j < 3*5; ++j) { pz[j] = drand48 (); }

      estep (data[i].inputs.alpha,
             5,
             data[i].inputs.logbeta,
             3,
             pz,
             data[i].inputs.priorz,
             clamp,
             data[i].inputs.ratings,
             8,
             1);

      for (unsigned int j = 0; j < 3*5; ++j)
        {
          assert (fabs (pz[j] - data[i].pz[j]) <=
                  1e-4 * (1 + fabs (pz[j]) + fabs (data[i].pz[j])) ||
                  (fprintf (stderr, "%u: %g ?= %g\n", j, pz[j], data[i].pz[j]), 0));
        }
    }
}

static void
test_estep_clamp_symmetric (void)
{
  EstepClampTestDatum data[] = 
    {{{{0.898382, 0.0401865, 0.993249, 0.19873,  0.106275}, {{1, 2, 0}, {0, 1, 0}, {1, 0, 4}, {3, 0, 2}, {2, 1,  1}, {0, 0, 1}, {2, 0, 2}, {3, 1, 2}}, {0, 0.455184, 0.403071,  0.110551, 0.491433, 0.575695, 0, 0.450771, 0.213418, 0.765882,  0.901541, 0.172255, 0, 0.796676, 0.455538, 0.804956, 0.428071,  0.450829, 0, 0.988548, 0.698127, 0.535427, 0.666901, 0.0901658, 0,  0, 0.65794, 0.542179, 0.468171, 0.983891, 0.202756, 0, 0.139107,  0.35762, 0.492458, 0.627061, 0.688337, 0, 0.144202, 0.726576,  0.72552, 0.516081, 0.347526, 0, 0.271038, 0.920564, 0.0880109,  0.896698, 0.28249, 0, 0, 0.222437, 0.552584, 0.229797, 0.192324,  0.564497, 0, 0.0104049, 0.761625, 0.208433, 0.361741, 0.871297, 0,  0.404005, 0.715975, 0.73468, 0.182961, 0.259803, 0, 0.989399,  0.00916058, 0.666879, 0.912277, 0.718361, 0, 0, 0.088597,  0.578868, 0.0155788, 0.435871, 0.86616, 0, 0.0262849, 0.785782,  0.243547, 0.301663, 0.01588, 0, 0.0241569, 0.0351132, 0.939922,  0.144583, 0.620152, 0, 0.319138, 0.205241, 0.961622, 0.360349,  0.329739, 0}, {0.196081, 0.294742, 0.448072}, {1, -1,  0}}, {2.4425e-7, 0.999995, 1.17064e-6, 1.84392e-6,  1.24329e-6, 0.275002, 0.0198767, 0.578024, 0.0726006, 0.0544965,  0.999997, 6.92792e-7, 7.91859e-7, 8.50257e-7,  5.01162e-7}}, {{{0.432494, 0.175507, 0.241324, 0.689589,  0.646711}, {{1, 2, 1}, {2, 0, 2}, {3, 2, 0}, {0, 0, 0}, {1, 1,  2}, {0, 1, 1}, {2, 2, 1}, {0, 1, 3}}, {0, 0.93196, 0.939661,  0.673709, 0.622554, 0.896847, 0, 0.999739, 0.529127, 0.00240253,  0.577709, 0.794497, 0, 0.567505, 0.642054, 0.24797, 0.598417,  0.272762, 0, 0.193981, 0.636592, 0.490933, 0.556888, 0.761488, 0,  0, 0.461085, 0.249609, 0.867299, 0.114777, 0.529125, 0, 0.309948,  0.19359, 0.492222, 0.632278, 0.310209, 0, 0.664463, 0.48982,  0.0545695, 0.515712, 0.0969588, 0, 0.847766, 0.806599, 0.917295,  0.824196, 0.653785, 0, 0, 0.170007, 0.426362, 0.267308, 0.892297,  0.708922, 0, 0.176754, 0.400009, 0.77752, 0.179797, 0.866806, 0,  0.206419, 0.285298, 0.547518, 0.556597, 0.541955, 0, 0.795478,  0.492949, 0.0408852, 0.444997, 0.947712, 0, 0, 0.686349, 0.12359,  0.6208, 0.293927, 0.516342, 0, 0.697228, 0.353492, 0.40163,  0.80742, 0.520474, 0, 0.953483, 0.62411, 0.627624, 0.653669,  0.747064, 0, 0.338812, 0.0801052, 0.0970719, 0.205109, 0.543334,  0}, {0.587156, 0.0561867, 0.760112}, {1, 4, 4}}, {0.0000123792,  0.999975, 4.20337e-6, 3.95348e-6, 4.10721e-6,  1.34087e-6, 2.69232e-6, 1.83384e-6, 2.04954e-6,  0.999992, 0.0000119082, 0.0000118188, 0.0000134742, 5.30065e-6,  0.999957}}, {{{0.139312, 0.301695, 0.384465, 0.235369,  0.785819}, {{3, 2, 3}, {3, 1, 0}, {3, 0, 2}, {3, 0, 3}, {1, 0,  2}, {3, 1, 2}, {1, 2, 3}, {0, 2, 0}}, {0, 0.900065, 0.577045,  0.714894, 0.832336, 0.275955, 0, 0.949421, 0.0612258, 0.0852723,  0.937142, 0.869316, 0, 0.964154, 0.880164, 0.393808, 0.28216,  0.907967, 0, 0.120052, 0.798185, 0.381353, 0.975371, 0.98074, 0,  0, 0.49649, 0.996888, 0.740002, 0.194921, 0.596425, 0, 0.419843,  0.0251076, 0.362584, 0.320471, 0.470422, 0, 0.963882, 0.277312,  0.383329, 0.601106, 0.999728, 0, 0.397148, 0.989521, 0.318947,  0.0917609, 0.277097, 0, 0, 0.191336, 0.937594, 0.11639, 0.296356,  0.694846, 0, 0.940706, 0.376388, 0.101436, 0.0984205, 0.520863, 0,  0.351281, 0.738851, 0.77795, 0.0504403, 0.387399, 0, 0.461539,  0.394621, 0.449334, 0.387671, 0.0643908, 0, 0, 0.4051, 0.130387,  0.29591, 0.787294, 0.213764, 0, 0.192794, 0.17952, 0.490938,  0.518919, 0.252088, 0, 0.803131, 0.389502, 0.420498, 0.731225,  0.451851, 0, 0.650651, 0.642548, 0.680785, 0.0644516, 0.189112,  0}, {0.247927, 0.231451, 0.676781}, {-1, 1, -1}}, {0.052883,  0.183035, 0.317881, 0.059981, 0.38622, 5.06918e-6, 0.999987,  4.79162e-6, 1.69994e-6, 1.90176e-6, 0.216217, 0.179608,  0.0491573, 0.410417, 0.144601}}}; 

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      double pz[3*5];

      for (unsigned int j = 0; j < 3*5; ++j) { pz[j] = drand48 (); }

      estep (data[i].inputs.alpha,
             5,
             data[i].inputs.logbeta,
             3,
             pz,
             data[i].inputs.priorz,
             data[i].inputs.clamp,
             data[i].inputs.ratings,
             8,
             1);

      for (unsigned int j = 0; j < 3*5; ++j)
        {
          assert (fabs (pz[j] - data[i].pz[j]) <=
                  1e-4 * (1 + fabs (pz[j]) + fabs (data[i].pz[j])) ||
                  (fprintf (stderr, "%u: %g ?= %g\n", j, pz[j], data[i].pz[j]), 0));
        }
    }
}

int 
main (void)
{
  srand48 (69);

  test_estep ();
  test_estep_clamp ();
  test_estep_symmetric ();
  test_estep_clamp_symmetric ();

  /* TODO: copy longer test vectors in */

  return 0;
}
